`timescale 1 ns / 100 ps

module spi_tb;

initial begin
    $dumpfile("spi_tb.vcd"); //生成的vcd文件名称
    $dumpvars(0, spi_tb);    //tb模块名称
    $timeformat(-9, 2, "ns", 4);
end

localparam TCLK = 20;

reg clk;
reg rst_n;

initial begin
    #0 clk = 0;
    forever
        #(TCLK / 2) clk = ~clk;
end

initial begin
    #0 rst_n = 0;
    #20 rst_n = 1;
end

reg [9:0]   HADDR;
reg [31:0]  HWDATA;
reg         HWRITE;
reg [2:0]   HSIZE;
reg [2:0]   HBURST;
reg         HSEL;
reg [1:0]   HTRANS;
reg         HREADY_IN;

wire         HREADY_OUT;
wire [31:0]  HRDATA;
wire [1:0]   HRESP;

wire spi_sclk;
wire spi_mosi;
wire spi_miso;
wire spi_ss;


initial begin
    HADDR = 32'b0;
    HWRITE = 1'b0;
    HWDATA = 32'b0;

    HSIZE = 3'b0;
    HBURST = 3'b0;
    HSEL = 1'b0;
    HTRANS = 2'b00;
    HREADY_IN = 1'b1;
end

task ahb_read;
    input [7:0] addr;
    output integer value;
    begin
        @(posedge clk);
        #1;

        HSEL = 1'b1;
        HTRANS = 2'b10;
        HADDR = addr;
        HWRITE = 1'b0;
        HWDATA = {32{1'bx}};
        HSIZE = 3'b010;

        @(posedge clk);
        #1;
        // HADDR = 8'hxx;
        HTRANS = 2'b00;

        repeat(4) begin
            @(posedge clk);
            if(HREADY_OUT) begin
                $display("[%m]#%t INFO: Read Value: 0x%08x @ 0x%08x", $time, HRDATA, HADDR);
                #1;
                value = HRDATA;
                HSEL = 1'b0;
                HADDR = 8'h0;
                HWRITE = 1'b0;
                HWDATA = {32{1'bx}};
                HSIZE = 3'b000;

                HTRANS = 2'b0;
                // repeat(2) @(posedge clk);
                disable ahb_read;
            end
        end
        $stop;
    end
endtask

task ahb_write;
    input [7:0] addr;
    input integer data;
    begin
        @(posedge clk);
        #1;

        HSEL = 1'b1;
        HTRANS = 2'b10;
        HADDR = addr;
        HWRITE = 1'b1;
        HWDATA = {32{1'bx}};
        HSIZE = 3'b010;

        @(posedge clk);
        #1;
        // HADDR = 8'hxx;
        HTRANS = 2'b00;
        HWDATA = data;

        repeat(4) begin
            @(posedge clk);
            if(HREADY_OUT) begin
                $display("[%m]#%t INFO: Write Value: 0x%08x @ 0x%08x", $time, HWDATA, HADDR);
                #1;
                HSEL = 1'b0;
                HADDR = 8'h0;
                HWRITE = 1'b0;
                HWDATA = {32{1'bx}};
                HSIZE = 3'b000;

                HTRANS = 2'b0;
                // repeat(2) @(posedge clk);
                disable ahb_write;
            end
        end
        $stop;
    end
endtask

integer out;
initial begin
    @(posedge rst_n);
    repeat(8) @(posedge clk);
    ahb_write(8'h04, 32'h0000_0000);
    ahb_write(8'h08, 32'h0000_0000);
    ahb_write(8'h0C, 32'h0000_0000);
    ahb_write(8'h10, 32'h0000_0000);
    ahb_write(8'h14, 32'h0000_0000);
    ahb_write(8'h18, 32'h0000_0000);
    repeat(8) @(posedge clk);

    ahb_read(8'h04, out);

    ahb_write(8'h00, 32'h1100_0000);
    ahb_write(8'h00, 32'h0000_001a);
    ahb_write(8'h00, 32'h1000_0000);

    repeat(128) @(posedge clk);
    $stop;
end

spi_ahb_wrap dut(
                 .clk(clk),
                 .reset_n(rst_n),

                 // AHB Slave
                 .sHADDR(HADDR[9:2]),
                 .sHWDATA(HWDATA),
                 .sHWRITE(HWRITE),
                 .sHREADYOUT(HREADY_OUT),
                 .sHSIZE(HSIZE),
                 .sHBURST(HBURST),
                 .sHSEL(HSEL),
                 .sHTRANS(HTRANS),
                 .sHRDATA(HRDATA),
                 .sHRESP(HRESP),
                 .sHREADY(HREADY_IN),
                 //    .sHPROT,

                 .spi_sclk(spi_sclk),
                 .spi_mosi(spi_mosi),
                 .spi_miso(1'b0),
                 .spi_ss(spi_ss)
             );

endmodule


